﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Meta.Numerics.Statistics.Distributions;

namespace ExcelAddIn1
{
    /**
     * Implementation of an independent, two-sided T-test.
     */
    class Test_T_independent_2S : Test
    {
        public Test_T_independent_2S(DataContainer data)
        {
            this.data = data;
            res = new List<String>();
        }

        public override string GetInfo()
        {
            String s = "Performs a Two-sided Student's T-test to check for significant differences between two datasets. ";
            s += "The test requires that the datasets are normally distributed, have equal variances and are independent.";
            return s;
        }

        public override void RunTest()
        {
            res.Add("Two-sided independent T-test");

            //Error check
            if (data.GetNoSets() != 2)
            {
                res.Add("Two datasets is required!");
                return;
            }

            //Get data sets
            DataSet d1 = data.GetDataSet(0);
            DataSet d2 = data.GetDataSet(1);

            //Test for equal variance
            Test_EqualVariance ev = new Test_EqualVariance(data);
            ev.RunTest();
            bool equalV = ev.IsEqual();

            //Calculate the approximated standard error for the
            //difference between the means
            double o = 0.0;
            if (equalV)
            {
                //Calculate pooled variance SP
                double sp = Math.Sqrt(((d1.GetN() - 1) * Math.Pow(d1.GetStDev(), 2) + (d2.GetN() - 1) * Math.Pow(d2.GetStDev(), 2)) / (double)(d1.GetN() + d2.GetN() - 2));
                o = sp * Math.Sqrt(1.0 / (double)d1.GetN() + 1.0 / (double)d2.GetN());
            }
            else
            {
                o = Math.Sqrt(Math.Pow(d1.GetStDev(), 2) / (double)d1.GetN() + Math.Pow(d2.GetStDev(), 2) / (double)d2.GetN());
            }

            //Find Critical T
            double DF = (double)(d1.GetN() + d2.GetN() - 2);
            StudentDistribution tdist = new StudentDistribution(DF);
            double TcLow = tdist.InverseLeftProbability(alpha / 2.0);
            double TcHigh = tdist.InverseRightProbability(alpha / 2.0);

            //Calculate T-score
            double Xdiff = d1.GetMean() - d2.GetMean() - assumedMeanDiff;
            double T = Xdiff / o;

            //Calculate P-value
            double p = tdist.RightProbability(T) * 2.0;
            
            //Results
            res.Add(";" + d1.GetName() + ";" + d2.GetName() + ";-");
            res.Add("N;" + d1.GetN() + ";" + d2.GetN() + ";-");
            res.Add("Mean;" + d1.GetMean().ToString("F2") + ";" + d2.GetMean().ToString("F2"));
            res.Add("StDev;" + d1.GetStDev().ToString("F2") + ";" + d2.GetStDev().ToString("F2"));
            res.Add("DoF;" + (int)DF);
            res.Add("α;" + alpha + ";;-");
            res.Add("P-value;" + p.ToString("F3"));
            if (assumedMeanDiff != 0.0)
            {
                res.Add("Diff in means;" + assumedMeanDiff.ToString("F2"));
            }
            res.Add("T-score;" + T.ToString("F2"));
            res.Add("T-crit;" + TcHigh.ToString("F2"));
            if (T < TcLow || T > TcHigh)
            {
                res.Add("Result;Significant difference at level " + p.ToString("F3"));
            }
            else
            {
                res.Add("Result;No difference (significance level " + p.ToString("F3") + ")");
            }
            res.Add(";;;-");
        }
    }
}
